package server

import (
	"fmt"

	"gitee.com/zawei/yggdrasil/pkg"
	"gitee.com/zawei/yggdrasil/pkg/transport"
)

type Info struct {
	Instance
	Scheme   string                `json:"scheme"` // 协议：HTTP GRPC
	Group    string                `json:"group"`  //用于区分不懂的协议或者不同的功能
	Kind     transport.ServiceKind `json:"kind"`
	Services map[string]*Service   `json:"methods"` //服务列表，同一个类型下的不同服务
	Selector map[string]string     `json:"selector"`
}

func (si Info) Endpoint() string {
	return fmt.Sprintf("%s://%s", si.Scheme, si.Address())
}

func (si Info) Address() string {
	return fmt.Sprintf("%s:%d", si.Ip, si.Port)
}

// Instance
type Instance struct {
	AppName  string            `json:"appName"` // 实例的标识名字
	AppID    string            `json:"appId"`   // APP ID
	Ip       string            `json:"ip"`
	Port     uint64            `json:"port"`
	Weight   float64           `json:"weight"`
	Disable  bool              `json:"enable"`
	Healthy  bool              `json:"healthy"`
	Cluster  string            `json:"cluster"` //同一个服务的不同集群
	Metadata map[string]string `json:"metadata"`
	//临时实例： 不会在注册中心持久化存储，心跳超时则会被注册中心删除。
	//持久化实例： 会被注册中心持久化存储，即使心跳超时，该实例也不会被注册中心删除，只会被设置成不健康状态。
	Ephemeral bool `json:"ephemeral"`
}

func (i Instance) Address() string {
	return fmt.Sprintf("%s:%d", i.Ip, i.Port)
}

// Service ...
type Service struct {
	Name     string            `json:"name,omitempty"`
	Metadata map[string]string `json:"metadata,omitempty"`
	Methods  []string          `json:"methods,omitempty"`
}

type Route struct {
	// 权重组，按照
	WeightGroups []WeightGroup
	// 方法名
	Method string
}

type WeightGroup struct {
	Group  string
	Weight int
}

type Option func(c *Info)

func WithScheme(scheme string) Option {
	return func(c *Info) {
		c.Scheme = scheme
	}
}

func WithAddress(ip string, port uint64) Option {
	return func(c *Info) {
		c.Ip = ip
		c.Port = port
	}
}

func WithKind(kind transport.ServiceKind) Option {
	return func(c *Info) {
		c.Kind = kind
	}
}

func WithMetaData(key, value string) Option {
	return func(c *Info) {
		c.Metadata[key] = value
	}
}

func WithGroup(group string) Option {
	return func(c *Info) {
		c.Group = c.Group
	}
}

func WithWeight(group string) Option {
	return func(c *Info) {
		c.Group = c.Group
	}
}

func NewInfo(opts ...Option) Info {
	info := Info{
		Kind: transport.ServiceUnknown,
		Instance: Instance{
			AppName:   pkg.AppName(),
			AppID:     pkg.AppID(),
			Metadata:  make(map[string]string),
			Ephemeral: true,
		},
		Services: map[string]*Service{},
		Selector: map[string]string{},
	}
	for _, o := range opts {
		o(&info)
	}
	if info.Group == "" {
		info.Group = fmt.Sprintf("%s.%s", info.Kind, info.Scheme)
	}
	return info
}
